let num: number = 123
let myNull: null = null
let myUndefined: undefined = undefined
let myName: string = `${myUndefined}`
function fnc1(): void {
    return
}
function fnc2(): void {
    return undefined
}
let obj1: Object = {}
let obj2: object = {}
interface Axxx {
    name: string
    readonly id: number
    age: number
    [prop: string]: unknown
    cb: () => boolean
}

let obj3: Axxx = {
    id: 1,
    name: 'xxx',
    age: 18,
    sex: 'male',
    nickname: {
        name: 'liming'
    },
    cb: () => {
        return false
    }
}
obj3.sex = 123
console.log(obj3)

interface Bxxx {
    (name: string): number[]
}

let obj4: Bxxx = (name: string) => {
    return [1, 2, 3]
}


// 数组类型
interface Person {
    name: string,
    age: number
}

let arr: Person[] = [
    { name: 'zhangsan', age: 18 },
    { name: 'lisi', age: 19 },
    { name: 'wangwu', age: 20 }
]

// 二维数组
let arr2: Array<Array<number>> = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

let arr3: number[][] = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]
// 大杂烩数组
let arr4: any[] = [
    1,
    '2',
    true,
    { name: 'zhangsan', age: 18 },
    [1, 2, 3]
]


function a(...args: number[]) {
    console.log(args);

}
a(1, 2, 3)


// arguments
function b(...args: number[]) {
    console.log(arguments);

}
b(1, 2, 3, 4, 5)

function c(...args: number[]) {
    let a: IArguments = arguments

}
c(1, 2, 3, 4, 5)
function d(...args: number[]) {
    let a: CeateIArguments = arguments

}
d(1, 2, 3, 4, 5)
interface CeateIArguments {
    [index: number]: number
    length: number
    callee: Function
}

console.log("--------------------函数--------------------")

// 函数
function add(a: number, b: number): number {
    return a + b
}
console.log(add(1, 2));
//  箭头函数写法
const add2 = (a: number, b: number): number => {
    return a + b
}

//返回对象
interface User {
    username: string,
    password: string
}
function user(user: User): User {
    return user
}
console.log(user({ username: "admin", password: "123456" }))

// this的类型
interface Obj5 {
    arrNum: number[],
    add: (this: Obj5, num: number) => void
}
let obj5: Obj5 = {
    arrNum: [1, 2, 3],
    add(this: Obj5, num: number) {
        this.arrNum.push(num)
    }
}
obj5.add(4)
console.log(obj5.arrNum);

console.log("----------------函数重载-------------")
const admin: number[] = [1, 2, 3, 4, 5, 6]

function getAdmin(ids?: number[] | number): number[] {
    if (typeof ids == "number") {
        return admin.filter(v => v == ids)
    } else if (Array.isArray(ids)) {
        admin.push(...ids)
        return admin
    } else {
        return admin
    }
}
console.log(getAdmin());

// 联合类型
console.log("----------------联合类型-------------")
let fn = function (num: number | boolean): boolean {
    return !!num
}
console.log(fn(1));

// 交叉类型
console.log("----------------交叉类型-------------")
interface Person {
    name: string,
    age: number
}
interface Sex {
    sex: string
}
function personFn(man: Person & Sex): void {
    console.log(man);

}

personFn(
    { name: "zhangsan", age: 18, sex: "1" }
)



// 类型断言
console.log("----------------类型断言-------------")
function getLength(str: number | string): void {
    console.log((str as string).length);

}
getLength("123456")
getLength(123456)  //tip 类型断言只能欺骗编译器不报错，number类型是没有length的方法，所以是undefined

// 这个例子也证明了类型断言只能欺骗编译器，不会帮你转换为boolean类型
function getBolean(str: number | boolean): boolean {
    return str as boolean;
}
console.log(getBolean(1));

// 内置对象
console.log("----------------内置对象-------------")

const date: Date = new Date()
const reg: RegExp = new RegExp("/\W/")
const error: Error = new Error("错误")
const xhr: XMLHttpRequest = new XMLHttpRequest()
const math:String=new String()

let div: NodeListOf<HTMLDivElement> = document.querySelectorAll("div")


let local: Storage = localStorage
let loacltion: Location = location
let promise: Promise<string> = new Promise((resolve, reject) => {
    resolve("成功")
})
promise.then(res => res.length
)
let cookie: string = document.cookie


// class
console.log("----------------class-------------")
interface Options {
    el: string
}
interface Vuecls {
    options: Options,
    init: () => void
}
interface Vnode{
    tag:string,
    text?:string,
    children?:Vnode[]
}
class Dom{
    createElement(el:string){
        return document.createElement(el)
    }
    setText(el:HTMLElement,text:string){ 
        el.textContent = text
    }
    render(data:Vnode){
        let root =this.createElement(data.tag)
        if(data.children&&Array.isArray(data.children)){
            data.children.forEach(item=>{
                this.render(item)
            })
        }else{
           let child= this.setText(root,data.text)
           root.appendChild(child)
        }
        return root
    }
}

class Vue implements Vuecls {
    options: Options
    constructor(options: Options) {
        this.options = options
        this.init()
    }
    init(): void {
        let data:Vnode={
            tag:"div",
            text:"",
            children:[
                {tag:"div",text:"我是子节点1"},
                {tag:"div",text:"我是子节点2"}
            ]
        }
    }
}
new Vue({
    el: "#app"
})